package cn.bluech.lib.appbase;

import android.text.TextUtils;
import android.util.Log;

import java.io.File;
import java.io.FileOutputStream;
import java.io.OutputStream;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;
import java.util.TimeZone;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

import cn.bluech.lib.utils.StreamUtils;

/**
 * Description:
 * Create by Codeant on 2019/9/3.
 */
public class ILog {
    private static final String TAG = "ILog";
    public static final int VERBOSE = 0;
    public static final int DEBUG   = 1;
    public static final int INFO    = 2;
    public static final int WARN    = 3;
    public static final int ERROR   = 4;
    public static final int ASSERT  = 5;
    public static final int DISABLE = 6;

    private static boolean isEnable = true;
    // 存储成文件的log等级，一般为INFO。默认不存储
    private static int saveLevel = DISABLE;
    private static String storageDir;
    private static LogWriter writer;

    public static void setStorageDir(String dir) {
        ILog.storageDir = dir;
        if(null!=writer)
            writer.release();
        if(!TextUtils.isEmpty(ILog.storageDir))
            writer = new LogWriter(dir);
        else
            writer = null;
    }

    public static void setEnable(boolean isEnable) {
        ILog.isEnable = isEnable;
    }

    public static boolean isEnable() {
        return isEnable;
    }

    public static void setLog2FileLevel(int level){
        saveLevel = level;
    }

    public static void v(String tag, String msg){
        if(!isEnable)
            return;

        Log.v(tag,msg);
        if((saveLevel<=VERBOSE)&&(null!=writer)){
            writer.write(VERBOSE,tag,msg);
        }
    }

    public static void d(String tag, String msg){
        if(!isEnable)
            return;

        Log.d(tag,msg);
        if((saveLevel<=DEBUG)&&(null!=writer)){
            writer.write(DEBUG,tag,msg);
        }
    }

    public static void i(String tag, String msg){
        if(!isEnable)
            return;

        Log.i(tag,msg);
        if((saveLevel<=INFO)&&(null!=writer)){
            writer.write(INFO,tag,msg);
        }
    }

    public static void w(String tag, String msg){
        if(!isEnable)
            return;

        Log.w(tag,msg);
        if((saveLevel<=WARN)&&(null!=writer)){
            writer.write(WARN,tag,msg);
        }
    }

    public static void e(String tag, String msg){
        if(!isEnable)
            return;

        Log.e(tag,msg);
        if((saveLevel<=ERROR)&&(null!=writer)){
            writer.write(ERROR,tag,msg);
        }
    }

    private static class LogWriter{
        private static final long ONE_DAY_MS = 24*60*60*1000;
        private static final long TIME_OFFSET = TimeZone.getDefault().getRawOffset();
        private static DateFormat dateFormat = new SimpleDateFormat("HH:mm:ss", Locale.getDefault());
        private String dir;
        // 只能是单线程(单log文件)
        private ExecutorService executor = Executors.newSingleThreadExecutor();
        private Date fileDate;
        private OutputStream os;

        LogWriter(String dir){
            this.dir = dir;
            createFile(dir);
        }

        public void release(){
            if(executor.isShutdown())
                return;
            executor.execute(new Runnable() {
                @Override
                public void run() {
                    StreamUtils.close(os);
                    os = null;
                    executor.shutdown();
                }
            });
        }

        private void createFile(String dir){
            if(TextUtils.isEmpty(dir))
                return;

            fileDate = new Date();
            String fileName = new SimpleDateFormat("yyyy-MM-dd",Locale.getDefault())
                    .format(fileDate)+".log";
            File logFile;
            if(dir.endsWith(File.separator)){
                logFile = new File(dir+fileName);
            }else
                logFile = new File(dir+File.separator+fileName);

            // 创建目录
            File parentFile = logFile.getParentFile();
            if(!parentFile.exists()){
                parentFile.mkdirs();
            }

            try {
                logFile.createNewFile();
                os = new FileOutputStream(logFile);
            } catch (Exception e) {
                e.printStackTrace();
                os = null;
            }
        }

        private boolean isSameDay(Date d1, Date d2){
            // 可能不一定比转换成字符串后判断字符串是否相等
            long day1 = (d1.getTime()+TIME_OFFSET)/ONE_DAY_MS;
            long day2 = (d2.getTime()+TIME_OFFSET)/ONE_DAY_MS;

            return day1==day2;
        }

        public void write(final int level, final String tag, final String msg){
            if(null==os) {
                Log.d(TAG,"Log to file lose");
                return;
            }

            final Date date = new Date();
            executor.execute(new Runnable() {
                @Override
                public void run() {
                    if(!isSameDay(fileDate,date)){
                        // 一天一个文件
                        createFile(dir);
                    }

                    StringBuilder sb = new StringBuilder();
                    sb.append(dateFormat.format(date));
                    switch (level){
                        case VERBOSE: sb.append("V/"); break;
                        case DEBUG:   sb.append("D/"); break;
                        case INFO:    sb.append("I/"); break;
                        case WARN:    sb.append("W/"); break;
                        case ERROR:   sb.append("E/"); break;
                        case ASSERT:  sb.append("ASSERT/"); break;
                    }
                    sb.append(tag).append(": ");
                    sb.append(msg);
                    if(!msg.endsWith("\n"))
                        sb.append("\r\n");

                    try {
                        os.write(sb.toString().getBytes());
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            });
        }
    }
}
